package cn.slipi.admin.common.interceptor;

import cn.slipi.admin.common.annotation.NoCheckSpecial;
import cn.slipi.admin.common.exception.base.BizException;
import cn.slipi.admin.common.servlet.RequestWrapper;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 非法字符拦截器
 *
 * @author lee
 */
@Component
public class IllegalInterceptor implements HandlerInterceptor {

    /**
     * 定义script的正则表达式
     */
    private static final String REG_EX_SCRIPT = "<script[^>]*?>[\\s\\S]*?<\\/script>";

    /**
     * 定义style的正则表达式
     */
    private static final String REG_EX_STYLE = "<style[^>]*?>[\\s\\S]*?<\\/style>";

    /**
     * 定义HTML标签的正则表达式
     */
    private static final String REG_EX_HTML = "<[^>]+>";


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method m = handlerMethod.getMethod();
        RequestWrapper requestWrapper = new RequestWrapper(request);
        String requestBody = requestWrapper.getBody();
        if (exceptController(m)) {
            return true;
        }
        if (this.hasSpecial(requestBody)) {
            throw new BizException(10000, "illegal.char.err");
        }

        if (this.checkSQLInject(requestBody)) {
            throw new BizException(10000, "illegal.char.err");
        }
        return true;
    }

    private boolean hasSpecial(String content) {

        Pattern scriptPattern = Pattern.compile(REG_EX_SCRIPT, Pattern.CASE_INSENSITIVE);
        Matcher scriptMatcher = scriptPattern.matcher(content);

        Pattern stylePattern = Pattern.compile(REG_EX_STYLE, Pattern.CASE_INSENSITIVE);
        Matcher styleMatcher = stylePattern.matcher(content);

        Pattern htmlPattern = Pattern.compile(REG_EX_HTML, Pattern.CASE_INSENSITIVE);
        Matcher htmlMatcher = htmlPattern.matcher(content);

        // 如果请求参数中含有任意一种特殊字符
        return scriptMatcher.find() || styleMatcher.find() || htmlMatcher.find();
    }

    /**
     * 检查是否存在非法字符，防止js脚本注入
     *
     * @param str 被检查的字符串
     * @return true -字符串中存在非法字符，false-不存在非法字符
     */
    private boolean checkSQLInject(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        str = str.toLowerCase();
        // 判断黑名单
        String badStr = "#|^|~";
        String[] badStrArr = badStr.split("\\|");
        for (String s : badStrArr) {
            if (str.contains(s)) {
                return true;
            }
        }
        return false;
    }

    private boolean exceptController(Method m) {
        return m.isAnnotationPresent(NoCheckSpecial.class);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) {
        // DO NOTHING
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // DO NOTHING
    }
}
